/*************************************************************
   Copyright(C) 2020 by WuIslet
   All rights reserved.

   UIEditorData.cs
   UnityFramework

   Created by WuIslet on 2020-09-27

*************************************************************/
#define USE_LUA_CODE1
#define USE_CSHARP_CODE

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

[Serializable]
public class UIEditorData : ScriptableObject
{
    private enum childWindowEnum
    {
        子控件 = 1,
        //格子控件 = 2,
        私有子控件 = 3,
        活动专用子控件 = 4,
    }

    public int resUIID = 0;
    public string prefabPath = "";
    public string ScriptSymbol = "";
    public string ScriptFolder = "";
    public int isChild = 0; //0-Window; 1-child; 2-Grid; 3-privateChild; 4-activityChild

    [NonSerialized]
    private MySearchField<CtrlItemData.SearchModePreferencesEditorWindow> searchfield;
    [NonSerialized]
    public string searchText = "";
    public List<CtrlItemData> ctrlItemDatas;

    #region geters/seters
    public string GetScriptSymbol()
    {
        if (string.IsNullOrEmpty(ScriptSymbol))
        {
            var name = Path.GetFileNameWithoutExtension(prefabPath);
            return name;
        }
        return ScriptSymbol;
    }

    public GameObject GetRoot()
    {
        return root;
    }
    #endregion geters/seters

    public bool IsVaild()
    {
        return !string.IsNullOrEmpty(ScriptSymbol);
    }

    public void DoInit(string path, GameObject root)
    {
        prefabPath = path;
        foreach (var item in ctrlItemDatas)
        {
            item.RefreshTarget(root);
        }
    }

    public void ResetAll() // ==重要== 因为不知道为什么，从.asset文件load出来的UIEditorData实例里面会有root的引用，就算NonSerialized也不能修复这个问题，目前临时处理，增加主动清理方法。
    {
        _ctrlItemDrawers = null;
        root = null;
    }

    public void CheckDataCorrect()
    {
        if (string.IsNullOrEmpty(ScriptSymbol))
        {
            var name = Path.GetFileNameWithoutExtension(prefabPath);
            ScriptSymbol = name;
        }
    }

    public void OnDrawHead(bool isDebug)
    {
        var isWindow = isChild == 0;
        if (isWindow) //界面
        {
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.LabelField("界面类型：", "界面");
            EditorGUI.EndDisabledGroup();
        }
        else //child
        {
            var childEnum = (childWindowEnum)isChild;
            childEnum = (childWindowEnum)EditorGUILayout.EnumPopup("界面类型：", childEnum);
            isChild = (int)childEnum;
            if (isChild == 2)
            {
                resUIID = EditorGUILayout.DelayedIntField("配置id：", resUIID);
            }
            else
            {
                resUIID = 0;
            }
        }

        EditorGUI.BeginDisabledGroup(true);
        var prefabName = Path.GetFileNameWithoutExtension(prefabPath);
        EditorGUILayout.TextField("预制体名字：", prefabName);
        var symbol = EditorGUILayout.DelayedTextField("代码编号：", GetScriptSymbol());
        EditorGUI.EndDisabledGroup();
        if (!(string.IsNullOrEmpty(ScriptSymbol) && (symbol == Path.GetFileNameWithoutExtension(prefabPath))))
            ScriptSymbol = symbol;
        //ScriptFolder = EditorGUILayout.DelayedTextField("代码路径：", ScriptFolder);
    }

    [NonSerialized] private Rect scrollArea;
    [NonSerialized] private Vector2 _scrollPos;
    [NonSerialized] private List<ControlItemDrawer> _ctrlItemDrawers;
    [NonSerialized] private GameObject root;
    public void DrawUIControlData(bool isDebug)
    {
        if (searchfield == null)
        {
            searchfield = new MySearchField<CtrlItemData.SearchModePreferencesEditorWindow>();
            searchfield.DropdownSelectionDelegate = ChangeSearchMode;
        }

        if (root == null && !string.IsNullOrEmpty(prefabPath))
        {
            var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); //todo 归一root获取途径
            if (stage != null)
            {
                root = stage.prefabContentsRoot;
            }
            else if (Application.isPlaying)
            {
                root = UISceneToolWindow.playingWatchPrefab;
            }
            else
            {
                root = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
            }
        }
        CheckDrawers(searchText);
        EditorGUILayout.Space();

        EditorGUILayout.BeginVertical();

        EditorGUI.BeginDisabledGroup(!string.IsNullOrEmpty(searchText));
        {
            if (GUILayout.Button("+"))
            {
                AddControlAfter(-1);
            }

            if (GUILayout.Button(new GUIContent("一键添加所有控件"/*, "在你想要添加的gameobject上\n添加tag: UI_ControlData\n就能一键添加"*/)))
            {
                //var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
                //if (prefabStage != null) //手动保存prefab，因为使用objectid来索引对象的前提条件是需要保存下来，不保存的对象是拿不到objectid的。
                //{
                //    PrefabUtility.SaveAsPrefabAsset(prefabStage.prefabContentsRoot, prefabStage.assetPath);
                //    prefabStage.ClearDirtiness();
                //}
                CtrlItemDataHelper.AutoAddComponents(root, ctrlItemDatas);
                _ctrlItemDrawers = null;
                CheckDrawers(searchText);
            }

            if (UISceneToolWindow.isUseTagTool)
            {
                if (GUILayout.Button("将data里的数据，规范化应用到prefab里面"))
                {
                    CtrlItemDataHelper.AutoFormatPrefab(root, ctrlItemDatas);
                }
            }

            //if (GUILayout.Button("打印所有路径"))
            //{
            //    CtrlItemDataHelper.PrintAllPath(ctrlItemDatas);
            //}

            var hasNoneGameObject = false;
            for (int i = 0; i < _ctrlItemDrawers.Count; i++)
            {
                var itemData = _ctrlItemDrawers[i].getData();
                if (itemData.GetTargets(root, onlyGO:true) == null)
                {
                    if (!string.IsNullOrEmpty(itemData.TargetFileID) || !string.IsNullOrEmpty(itemData.name))
                    {
                        hasNoneGameObject = true;
                        break;
                    }
                }
            }
            if (hasNoneGameObject)
            {
                if (GUILayout.Button("尝试填补空控件"))
                {
                    var cnt = CtrlItemDataHelper.AutoFindComponents(root, ctrlItemDatas);
                    if (cnt > 0)
                    {
                        EditorUtility.DisplayDialog("错误", "尝试填补空控件失败，共" + cnt + "行", "OK");
                    }
                    _ctrlItemDrawers = null;
                    CheckDrawers(searchText);
                }
            }

            if (ctrlItemDatas.Count <= 0)
            {
            }
            else
            {
                if (GUILayout.Button("删除所有控件"))
                {
                    CtrlItemDataHelper.DeleteAllComponents(ctrlItemDatas);
                    _ctrlItemDrawers = null;
                    CheckDrawers(searchText);
                }
            }
        }
        EditorGUI.EndDisabledGroup();

        EditorGUI.BeginChangeCheck();
        searchText = searchfield.OnToolbarGUI(searchText);
        if (EditorGUI.EndChangeCheck())
        {
            _ctrlItemDrawers = null;
            CheckDrawers(searchText);
        }

        if (_ctrlItemDrawers.Count > 0)
        {
            if (UISceneToolWindow.isJump2Target)
            {
                var find = -1;
                for (int idx = 0; idx < _ctrlItemDrawers.Count; ++idx)
                {
                    if (_ctrlItemDrawers[idx].checkPath(UISceneToolWindow.selectionPath))
                    {
                        find = idx;
                        break;
                    }
                }
                if (find >= 0)
                {
                    //_scrollPos = new Vector2(scrollArea.width, (float)find / (_ctrlItemDrawers.Count - 1) * scrollArea.height); //todo  scrollArea只是外层的rect，目前没找到如何获取内层rect尺寸的方法，预估只能自己累加每个元素。
                }
            }

            using (var scrollView = new EditorGUILayout.ScrollViewScope(_scrollPos))
            {
                _scrollPos = scrollView.scrollPosition;
                for (int idx = 0; idx < _ctrlItemDrawers.Count; ++idx)
                {
                    var drawer = _ctrlItemDrawers[idx];
                    if (!drawer.Draw(root, isDebug))
                    {
                    }
                }
            }

            scrollArea = GUILayoutUtility.GetLastRect();
            if (UISceneToolWindow.isJump2Target)
            {
                UISceneToolWindow.isJump2Target = false;
            }
        }

        EditorGUILayout.EndVertical();
        GUILayout.FlexibleSpace();
    }

    public void AddControlAfter(ControlItemDrawer drawer)
    {
        int idx = _ctrlItemDrawers.IndexOf(drawer);
        Debug.Assert(idx != -1);

        AddControlAfter(idx);
    }

    public void RemoveControl(ControlItemDrawer drawer)
    {
        int idx = _ctrlItemDrawers.IndexOf(drawer);
        Debug.Assert(idx != -1);

        RemoveControl(idx);
    }

    #region Private
    private void ChangeSearchMode()
    {
        _ctrlItemDrawers = null;
        CheckDrawers(searchText);
    }
    private void CheckDrawers(string searchText)
    {
        if (_ctrlItemDrawers == null)
        {
            _ctrlItemDrawers = new List<ControlItemDrawer>(100);
            for (int index = 0; index < ctrlItemDatas.Count; ++index)
            {
                var item = ctrlItemDatas[index];
                if (item.CheckSearchText(searchText, index, searchfield.SearchMode))
                {
                    ControlItemDrawer drawer = new ControlItemDrawer(this, item, root);
                    drawer.getData().index = index;
                    _ctrlItemDrawers.Add(drawer);
                }
            }
        }
    }

    private void AddControlAfter(int idx)
    {
        CtrlItemData itemData = new CtrlItemData();
        ctrlItemDatas.Insert(idx + 1, itemData);

        ControlItemDrawer drawer = new ControlItemDrawer(this, itemData, root);
        _ctrlItemDrawers.Insert(idx + 1, drawer);
        for (int i = 0; i < _ctrlItemDrawers.Count; i++)
        {
            _ctrlItemDrawers[i].getData().index = i;
        }
    }

    private void RemoveControl(int idx)
    {
        ctrlItemDatas.RemoveAt(idx);
        _ctrlItemDrawers.RemoveAt(idx);
        for (int i = 0; i < _ctrlItemDrawers.Count; i++)
        {
            _ctrlItemDrawers[i].getData().index = i;
        }
    }
    #endregion Private

    private static Type UIEditorDataType = typeof(UIEditorData);
    public string Serialization()
    {
        StringBuilder result = new StringBuilder();
        foreach (var fieldInfo in UIEditorDataType.GetFields(BindingFlags.Public | BindingFlags.Instance))
        {
            if (fieldInfo.Name == "ScriptSymbol")
            {
#if USE_LUA_CODE
                result.Append("pathLua");
                result.Append(" = \"UI/MVVM/GenerateCode/");
                result.Append(ScriptSymbol);
                result.Append("View\"");
                result.Append(", ");
                if (isChild == 0)
                {
                    result.Append("defaultVMPath");
                    result.Append(" = \"UI/");
                    if (!string.IsNullOrEmpty(ScriptFolder))
                    {
                        result.Append(ScriptFolder);
                        result.Append("/");
                    }
                    result.Append(ScriptSymbol);
                    result.Append("Window");
                    result.Append("\"");
                    result.Append(", ");
                }
#endif
#if USE_CSHARP_CODE
                result.Append("viewType");
                result.Append(" = typeof(");
                result.Append(fieldInfo.GetValue(this));
                result.Append("View)");
                result.Append(", ");
#endif
                continue;
            }

            if (fieldInfo.Name == "searchText")
                continue;

            if (fieldInfo.Name == "ctrlItemDatas")
                continue;

            if (fieldInfo.Name == "prefab")
                continue;

            if (fieldInfo.Name == "prefabPath")
            {
                var path = prefabPath;
                if (path.EndsWith(".prefab"))
                {
                    path = path.Remove(path.Length - 7);
                }
                if (path.StartsWith(EditorPathConfig.UIPrefabModelRoot))
                {
                    path = path.Replace(EditorPathConfig.UIPrefabModelRoot, "");
                }
                result.Append("prefab");
                result.Append(" = \"");
                result.Append(path);
                result.Append("\"");
                result.Append(", ");
                continue;
            }

            if (fieldInfo.Name == "ScriptFolder")
                continue;

            result.Append(fieldInfo.Name);
            result.Append(" = ");
            if (fieldInfo.FieldType == typeof(string))
            {
                result.Append("\"");
            }

            result.Append(fieldInfo.GetValue(this));

            if (fieldInfo.FieldType == typeof(string))
            {
                result.Append("\"");
            }
            result.Append(", ");
        }

        return result.ToString();
    }
}
